#ifndef __AAA传说中的建材批发__
#define __AAA传说中的建材批发__

#include <iostream>
#include <pthread.h>
#include <semaphore.h>
#include <vector>
#include <string>
#include <unistd.h>
#include <ctime>
using namespace std;
#define defaultnum 10
#define THREADS 3

class threadData
{
public:
    threadData(int num)
    {
        name_ = "Thread-" + to_string(num);
    }
    string getthread()
    {
        return name_;
    }

private:
    string name_;
};

template <class T>
class Blockqueue
{
public:
    Blockqueue()
    {
        queue_.resize(cat);
        pthread_mutex_init(&cmutex_, nullptr);
        // pthread_mutex_init(&pmutex_, nullptr);

        sem_init(&cdata_, 0, 0);    // 消费者一开始的资源(商品)为空
        sem_init(&pspace_, 0, cat); // 生产者一开始的资源(空间)为满
    }

    // 创建一个CP模型，用环形队列，信号量让c和p能同时消费和生产
    static void *custom(void *args)
    {
        Blockqueue<T> *rs = static_cast<Blockqueue<T> *>(args);
        while(true)
        {
            rs->P(&(rs->cdata_));//申请资源
            rs->Lock(&(rs->cmutex_));
            T data = rs->Pop();
            rs->V(&(rs->pspace_));//给生产者一个空间资源，要在pop操作之后
            rs->Unlock(&(rs->cmutex_));
            //处理数据
            data.run();
            cout << "消费者: " << pthread_self() << "向你报道! " << data.GetResult().c_str() << endl;
        }
    }

    //启动线程池
    void start()
    {
        for (int i = 0; i < THREADS; i++)
        {
            pthread_t tid;
            pthread_create(&tid, nullptr, custom, this);
            ctids_.push_back(tid);
        }
        
    }
    void Lock(pthread_mutex_t *mutex)
    {
        pthread_mutex_lock(mutex);
    }
    void Unlock(pthread_mutex_t *mutex)
    {
        pthread_mutex_unlock(mutex);
    }

    // 资源减1
    void P(sem_t *sem)
    {
        sem_wait(sem);
    }

    // 资源加1
    void V(sem_t *sem)
    {
        sem_post(sem);
    }

    T Pop()
    {
        T data = queue_[cp];
        cp = (cp+1) % cat;
        return data;
    }
    void Push(T& data)
    {
        P(&pspace_);
        // Lock(&pmutex_);
        cout << "创建任务: " << data.GetTask().c_str() << endl;
        queue_[pp] = data;
        pp = (pp+1) % cat;
        V(&cdata_);
        // Unlock(&pmutex_);
    }

    ~Blockqueue()
    {

        pthread_mutex_destroy(&cmutex_);
        //pthread_mutex_destroy(&pmutex_);

        sem_destroy(&cdata_);
        sem_destroy(&pspace_);
        for(const auto& e : ctids_ )
        {
            pthread_join(e, nullptr);
        }
    }

private:
    // 两种角色的锁
    pthread_mutex_t cmutex_;
    //pthread_mutex_t pmutex_;

    int cat = defaultnum;       // 环形队列的最大数
    vector<T> queue_;           // 模拟实现的环形队列
    int cp = 0;                 // 消费者的下标
    int pp = 0;                 // 生产者的下标
    vector<pthread_t> ctids_;  // 存放消费者们的tip
    // vector<threadData> ptids_;  // 存放生产者的线程数量

    // 两种角色的信号量
    sem_t cdata_;
    sem_t pspace_;
};

#endif